/**
 * UserPreferences.java 15 mai 2006
 * 
 * Copyright (c) 2006 Emmanuel PUYBARET / eTeks <info@eteks.com>. All Rights
 * Reserved.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */
package org.windu2b.jcaddie.model;

import java.beans.*;
import java.lang.ref.*;
import java.util.*;

import org.windu2b.jcaddie.model.Caddie.*;

/**
 * User preferences.
 * 
 * @author Emmanuel Puybaret, windu.2b
 */
public abstract class UserPreferences
{
	private Catalog	                                                   catalog;


	private Unit	                                                   unit;


	private PropertyChangeSupport	                                   propertyChangeSupport;


	private List<String>	                                           recentCaddies;


	private Map<Property, List<WeakReference<PropertyChangeListener>>>	propertiesListeners;



	/**
	 * Unit used for dimensions.
	 */
	public enum Unit
	{
		LITRE,

		GALLON,

		LIVRE,

		KILO,

		PIECE;

		public static float litreToGallon( float volume )
		{
			return volume * 3.7854118f;
		}




		public static float gallonToLitre( float volume )
		{
			return volume / 3.7854118f;
		}
	}




	public UserPreferences()
	{
		propertyChangeSupport = new PropertyChangeSupport( this );
	}




	/**
	 * Writes user preferences.
	 * 
	 * @throws RecorderException
	 *             if user preferences couldn'y be saved.
	 */
	public abstract void write() throws RecorderException;




	/**
	 * Adds the <code>listener</code> in parameter to these preferences.
	 */
	public void addPropertyChangeListener( String property,
	        PropertyChangeListener listener )
	{
		propertyChangeSupport.addPropertyChangeListener( property, listener );
	}




	/**
	 * Removes the <code>listener</code> in parameter from these preferences.
	 */
	public void removePropertyChangeListener( String property,
	        PropertyChangeListener listener )
	{
		propertyChangeSupport.removePropertyChangeListener( property, listener );
	}




	/**
	 * Returns the unit currently in use.
	 */
	public Unit getUnit()
	{
		return unit;
	}




	/**
	 * Changes the unit currently in use, and notifies listeners of this change.
	 * 
	 * @param unit
	 *            one of the values of Unit.
	 */
	public void setUnit( Unit unit )
	{
		if ( this.unit != unit )
		{
			Unit oldUnit = this.unit;
			this.unit = unit;
			propertyChangeSupport.firePropertyChange( "unit", oldUnit, unit );
		}
	}




	/**
	 * Returns the catalog.
	 */
	public Catalog getCatalog()
	{
		return catalog;
	}




	public void setCatalog( Catalog catalog )
	{
		this.catalog = catalog;
	}




	/**
	 * Returns an unmodifiable list of the recent caddies.
	 */
	public List<String> getRecentCaddies()
	{
		return Collections.unmodifiableList( recentCaddies );
	}




	/**
	 * Sets the recent caddies list and notifies listeners of this change.
	 */
	public void setRecentCaddies( List<String> recentHomes )
	{
		if ( !recentHomes.equals( this.recentCaddies ) )
		{
			List<String> oldRecentHomes = this.recentCaddies;
			this.recentCaddies = new ArrayList<String>( recentHomes );
			firePropertyChange( Property.RECENT_CADDIES, oldRecentHomes,
			        getRecentCaddies() );
		}
	}




	@SuppressWarnings( "unchecked" )
	private void firePropertyChange( Property property, Object oldValue,
	        Object newValue )
	{
		List<WeakReference<PropertyChangeListener>> propertyListeners = this.propertiesListeners
		        .get( property );
		if ( propertyListeners != null && !propertyListeners.isEmpty() )
		{
			PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
			        this, property.toString(), oldValue, newValue );
			// Work on a copy of propertiesListeners to ensure a listener
			// can modify safely listeners list
			WeakReference<PropertyChangeListener>[] listeners = propertyListeners
			        .toArray( new WeakReference[propertyListeners.size()] );
			for ( WeakReference<PropertyChangeListener> listenerReference : listeners )
			{
				PropertyChangeListener listener = listenerReference.get();
				if ( listener != null )
				{
					listener.propertyChange( propertyChangeEvent );
				}
				else
				{
					removePropertyChangeListener( property, listener );
				}
			}
		}
	}




	/**
	 * Removes the <code>listener</code> in parameter from these preferences.
	 */
	public void removePropertyChangeListener( Property property,
	        PropertyChangeListener listener )
	{
		List<WeakReference<PropertyChangeListener>> propertyListeners = this.propertiesListeners
		        .get( property );
		for ( Iterator<WeakReference<PropertyChangeListener>> it = propertyListeners
		        .iterator(); it.hasNext(); )
		{
			if ( it.next().get() == listener )
			{
				it.remove();
			}
		}
	}
}
